﻿using ShardingCore.Core.VirtualRoutes;

namespace ApplicationFrame.EntityFrameworkCore.Core
{
    public class TimeShardingStrategy<TEntity, TKey> : AbstractShardingStrategy<TEntity, TKey> where TEntity : class
    {
        private readonly TimeShardingGranularity _granularity;

        public TimeShardingStrategy(string shardingPropertyName, TimeShardingGranularity granularity = TimeShardingGranularity.Month)
        {
            _granularity = granularity;
            ShardingPropertyName = shardingPropertyName;
        }

        public override string GetTail(TKey shardingKey)
        {
            if (shardingKey is not DateTime && shardingKey is not DateTimeOffset)
                throw new ArgumentException("type must be DateTime or DateTimeOffset", nameof(shardingKey));

            return _granularity switch
            {
                TimeShardingGranularity.Year => $"{shardingKey:yyyy}",
                TimeShardingGranularity.Month => $"{shardingKey:yyyyMM}",
                TimeShardingGranularity.Day => $"{shardingKey:yyyyMMdd}",
                _ => throw new ArgumentOutOfRangeException()
            };
        }

        //public override List<string> GetTails()
        //{
        //    throw new NotImplementedException();
        //}

        public override Func<string, bool> GetRouteToFilter(TKey shardingKey, ShardingOperatorEnum shardingOperator)
        {
            var t = GetTail(shardingKey);
            switch (shardingOperator)
            {
                case ShardingOperatorEnum.GreaterThan:
                case ShardingOperatorEnum.GreaterThanOrEqual:
                    return (string tail) => string.Compare(tail, t, StringComparison.Ordinal) >= 0;
                case ShardingOperatorEnum.LessThan:
                    if (shardingKey is DateTime dt && dt.Date == dt || shardingKey is DateTimeOffset dts && dts.Date == dts.DateTime)
                        return (string tail) => string.Compare(tail, t, StringComparison.Ordinal) < 0;

                    return (string tail) => string.Compare(tail, t, StringComparison.Ordinal) <= 0;
                case ShardingOperatorEnum.LessThanOrEqual:
                    return (string tail) => string.Compare(tail, t, StringComparison.Ordinal) <= 0;
                case ShardingOperatorEnum.Equal:
                    return (string tail) => tail == t;
                default:
                    Console.WriteLine($"shardingKey: {shardingKey}, TimeShardingGranularity: {_granularity}, shardingOperator: {shardingOperator} is not equal scan all table tail");
                    return (string tail) => tail == t;
            }
        }
    }
}
